package com.googlecode.stew_faces.renderer;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import javax.el.ELContext;
import javax.el.ExpressionFactory;
import javax.el.ValueExpression;
import javax.faces.FacesException;
import javax.faces.application.Resource;
import javax.faces.component.UIComponent;
import javax.faces.component.UIViewRoot;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;
import javax.faces.render.Renderer;

import com.googlecode.stew_faces.component.HeadComponent;

public class HeadRenderer extends Renderer {

	private final static String PRIMEFACES_THEME_CONSTANT = "primefaces.THEME";

	@Override
	public void decode(FacesContext context, UIComponent component) {
	}

	@Override
	public void encodeBegin(FacesContext paramContext,
			UIComponent paramComponent) throws IOException {
		ResponseWriter writer = paramContext.getResponseWriter();

		List<UIComponent> usedComponents = new ArrayList<UIComponent>();
		HeadComponent head = (HeadComponent) paramComponent;

		if (head.getShortcutIcon() != null) {
			writer.startElement("link", null);
			writer.writeAttribute("rel", "shortcut icon", null);
			writer.writeAttribute("href", head.getShortcutIcon(), null);
			writer.endElement("link");
		}

		writer.startElement("head", paramComponent);
		encodeFacet(paramContext, paramComponent, "beforeStylesheet",usedComponents);
		
		UIComponent facet = paramComponent.getFacet("afterStylesheet");
		if (facet != null) {
			usedComponents.add(facet);
		}
		facet = paramComponent.getFacet("afterScript");
		if (facet != null) {
			usedComponents.add(facet);
		}

		try {
			handlePrimefacesTheme(paramContext);
		} catch (Exception e) {
			// do nothing, just log as error message
		}

		UIViewRoot viewRoot = paramContext.getViewRoot();
		List<UIComponent> list = viewRoot.getComponentResources(paramContext,
				"head");
		// handle resources
		if (list != null) {
			// render Stylesheets first, afterwards everything else
			// (javascript).
			// this is done because for faster pageloading
			for (UIComponent resource : list) {
				
				if (resource != null && !usedComponents.contains(resource)
						&& (resource.getRendererType()
								.equals("javax.faces.resource.Stylesheet"))) {
					
					resource.encodeAll(paramContext);
					
				}
			}
			encodeFacet(paramContext, paramComponent, "afterStylesheet",usedComponents);
			encodeFacet(paramContext, paramComponent, "beforeScript",usedComponents);
			for (UIComponent resource : list) {
				if (resource != null && !usedComponents.contains(resource)
						&& (resource.getRendererType().equals(
								"javax.faces.resource.Script"))) {
					resource.encodeAll(paramContext);
				}
			}
		}
		else
		{
			encodeFacet(paramContext, paramComponent, "afterStylesheet",usedComponents);
			encodeFacet(paramContext, paramComponent, "beforeScript",usedComponents);
		}
		
		encodeFacet(paramContext, paramComponent, "afterScript",usedComponents);

	}

	private void encodeFacet(FacesContext paramContext,
			UIComponent paramComponent, String paramFacet,List<UIComponent> paramUsedList) throws IOException {
		UIComponent facet = paramComponent.getFacet(paramFacet);
		if (facet != null) {
			
			paramUsedList.add(facet);
			facet.encodeAll(paramContext);
		}
	}

	@Override
	public void encodeChildren(FacesContext context, UIComponent component)
			throws IOException {
		// nothing to do
	}

	@Override
	public void encodeEnd(FacesContext context, UIComponent component)
			throws IOException {
		ResponseWriter writer = context.getResponseWriter();

		HeadComponent head = (HeadComponent) component;

		

		if (head.getTitle() != null) {
			writer.startElement("title", null);
			writer.write(head.getTitle());
			writer.endElement("title");
		}

		writer.endElement("head");
	}

	/*
	 * Copyright 2009-2011 Prime Technology.
	 * 
	 * Licensed under the Apache License, Version 2.0 (the "License"); you may
	 * not use this file except in compliance with the License. You may obtain a
	 * copy of the License at
	 * 
	 * http://www.apache.org/licenses/LICENSE-2.0
	 * 
	 * Unless required by applicable law or agreed to in writing, software
	 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
	 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
	 * License for the specific language governing permissions and limitations
	 * under the License.
	 */
	protected void handlePrimefacesTheme(FacesContext paramContext)
			throws IOException {
		// Theme
		String theme = null;
		ExternalContext extContext = paramContext.getExternalContext();
		ELContext elContext = paramContext.getELContext();
		String themeParamValue = extContext
				.getInitParameter(PRIMEFACES_THEME_CONSTANT);

		if (themeParamValue != null) {
			ExpressionFactory expressionFactory = paramContext.getApplication()
					.getExpressionFactory();
			ValueExpression ve = expressionFactory.createValueExpression(
					elContext, themeParamValue, String.class);

			theme = (String) ve.getValue(elContext);
		}

		if (theme == null || theme.equalsIgnoreCase("sam")) {
			encodeTheme(paramContext, "primefaces", "themes/sam/theme.css");
		} else if (!theme.equalsIgnoreCase("none")) {
			encodeTheme(paramContext, "primefaces-" + theme, "theme.css");
		}
	}

	/*
	 * Copyright 2009-2011 Prime Technology.
	 * 
	 * Licensed under the Apache License, Version 2.0 (the "License"); you may
	 * not use this file except in compliance with the License. You may obtain a
	 * copy of the License at
	 * 
	 * http://www.apache.org/licenses/LICENSE-2.0
	 * 
	 * Unless required by applicable law or agreed to in writing, software
	 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
	 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
	 * License for the specific language governing permissions and limitations
	 * under the License.
	 */
	protected void encodeTheme(FacesContext context, String library,
			String resource) throws IOException {
		ResponseWriter writer = context.getResponseWriter();
		writer.write("\n");

		Resource themeResource = context.getApplication().getResourceHandler()
				.createResource(resource, library);
		if (themeResource == null) {
			throw new FacesException("Error loading theme, cannot find \""
					+ resource + "\" resource of \"" + library + "\" library");
		} else {
			writer.startElement("link", null);
			writer.writeAttribute("type", "text/css", null);
			writer.writeAttribute("rel", "stylesheet", null);
			writer.writeAttribute("href", themeResource.getRequestPath(), null);
			writer.endElement("link");
		}
	}

}
